import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Point;
import java.awt.Toolkit;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;

//import java.util.Vector;

public class Map
{
	private Tile[][] map;
	private int[][] scentMap;
	private String source;
	Creature player;
	private Creature[] mob = new Creature[20];
	private TileSheet tiles;
	public final static int EAST = 0, SOUTH = 1, WEST = 2, NORTH = 3;
	static int block_start = 5, block_end = 16;
	FontHandler console;
	public boolean showScent = false;

	public Map(String file)
	{
		load(file);
		Image img = Toolkit.getDefaultToolkit().createImage("mtiles.PNG");
		tiles = new TileSheet(img, new Point(16, 16), getHeight(), getWidth());
		console = FontHandler.getInstance();

	}

	public void load(String file)
	{
		File f = new File(file);
		BufferedReader read = null;
		try
		{
			read = new BufferedReader(new FileReader(f));
		}
		catch (Exception e)
		{
			System.out.println(f + " not found...");
			e.printStackTrace();
		}
		try
		{
			String line = null;
			line = read.readLine();
			String palette = line;
			line = read.readLine();
			String blockPalette = line;
			int x, y, t;
			line = read.readLine();
			int space = line.indexOf(' ');
			y = Integer.parseInt(line.substring(0, space));
			x = Integer.parseInt(line.substring(space + 1));
			// LOAD THE MAP
			map = new Tile[x][y];
			scentMap = new int[x][y];
			for (int h = 0; h < x; ++h)
			{
				line = read.readLine();
				for (int w = 0; w < y; ++w)
				{
					space = palette.indexOf(line.charAt(w));
					t = blockPalette.charAt(space) - '0';
					if (t <= 1)
					{
						map[h][w] = new Tile(palette.indexOf(line.charAt(w)),
								t, false);
					}
					else
					{
						map[h][w] = new Tile(palette.indexOf(line.charAt(w)),
								t, true);
					}
				}
			}
			// LOAD THE PLAYER
			line = read.readLine();
			space = line.indexOf(' ');
			player = new Creature(Integer.parseInt(line.substring(0, space)),
					Integer.parseInt(line.substring(space + 1)), 80);
			// LOAD THE MOBS
			for (t = 0; t < 20; t++)
			{
				line = read.readLine();
				space = line.indexOf(' ');
				x = Integer.parseInt(line.substring(0, space));
				y = Integer.parseInt(line.substring(space + 1));
				mob[t] = new Creature(x, y, 100);
				map[y][x].setMob(100);
			}
			// TODO: LOAD THE ITEMS goes here
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}

	}

	public int getWidth()
	{
		return map[0].length;
	}

	public int getHeight()
	{
		return map.length;
	}

	public String doAction(Point p)
	{
		String text = "";
		switch ( map[p.y][p.x].getType() )
		{
		case 3: // This is a closed Door
			map[p.y][p.x].openDoor();
			text = "Door opened.";
			break;
		case 1: // This is an open Door
			map[p.y][p.x].closeDoor();
			text = "Door closed.";
			break;

		}

		return text;

	}

	public String getSource()
	{
		return source;
	}

	public void draw(Graphics g)
	{
		int dx = 0, dy = 0;
		for (int y = 0; y < 13; ++y)
		{
			dx = 0;
			for (int x = 0; x < 13; ++x)
			{
				if ((player.x + x - 6) >= 0 && (player.y + y - 6) >= 0
						&& (player.x + x) <= (getWidth() + 6)
						&& (player.y + y) <= (getHeight() + 6))
				{
					try
					{
						tiles.draw(g, x + dx, y + dy, getTile(player.x + x - 6,
								player.y + y - 6));
					}
					catch (Exception e)
					{
					}
					if (showScent)
					{
						try
						{
							int c = map[player.y + y - 6][player.x + x - 6].scent * 255 / 100;
							c = Math.min(c, 255);
							g.setColor(new Color(255, 0, 0, c));// Color.RED);
							g.fillRect(x + dx, y + dy, tiles.tileSize.x,
									tiles.tileSize.y);
						}
						catch (Exception e)
						{
						}
					}

				}

				dx += tiles.tileSize.x - 1;
			}
			dy += tiles.tileSize.y - 1;
		}
		player.draw(g, tiles);

	}

	public void movePlayer(int dir)
	{
		Point p = new Point();

		map[player.y][player.x].setMob(0);
		switch ( dir )
		{
		case NORTH:
			p.setLocation(player.x + 0, player.y - 1);
			player.dir = NORTH;
			console.addLine("North");
			break;
		case EAST:
			p.setLocation(player.x + 1, player.y + 0);
			player.dir = EAST;
			console.addLine("East");
			break;
		case SOUTH:
			p.setLocation(player.x + 0, player.y + 1);
			player.dir = SOUTH;
			console.addLine("South");
			break;
		case WEST:
			p.setLocation(player.x - 1, player.y + 0);
			player.dir = WEST;
			console.addLine("West");
			break;
		}

		if (!isBlocked(p))
		{
			if (!map[p.y][p.x].isOccupied())
			{
				player.move(p);
				map[p.y][p.x].addScent();
				// s = s + " (" + player.x + ", " + player.y + ")";
			}
			else
			{
				console.overWrite("An alien is in the way");
			}
		}
		else
		{
			console.overWrite("Blocked!");
		}
		map[player.y][player.x].setMob((player.dir + player.i));
		// spreadScent();

	}

	public void turnPlayer(int dir)
	{
		player.dir = dir;

	}

	public void moveMobs()
	{
		for (int b = 0; b < 20; b++)
		{

			Point p = new Point();
			map[mob[b].y][mob[b].x].setMob(0);
			if (lineOfSight(mob[b], player.x, player.y) )
			{
				int dx = player.x - mob[b].x;
				int dy = player.y - mob[b].y;

				if (Math.abs(dx) > Math.abs(dy))
				{
					if (dx > 0)
					{
						p.setLocation(mob[b].x + 1, mob[b].y + 0);
					}
					else
					{
						p.setLocation(mob[b].x - 1, mob[b].y + 0);

					}
				}
				else
				{
					if (dy > 0)
					{
						p.setLocation(mob[b].x + 0, mob[b].y + 1);
					}
					else
					{
						p.setLocation(mob[b].x + 0, mob[b].y - 1);

					}

				}

			}
			else
			{
				int dir = -1, a;
				
				a = map[mob[b].y][mob[b].x + 1].scent;
				
				if (map[mob[b].y][mob[b].x + 1].scent > 10)
				{
					dir = EAST;
				}
				if(map[mob[b].y + 1][mob[b].x].scent > 10)
				{
					if(map[mob[b].y + 1][mob[b].x].scent > a)
					{
						a = map[mob[b].y][mob[b].x + 1].scent;
						dir = SOUTH;
					}
					
				}
				if(map[mob[b].y][mob[b].x - 1].scent > 10)
				{
					if(map[mob[b].y][mob[b].x - 1].scent > a)
					{
						a = map[mob[b].y][mob[b].x - 1].scent;
						dir = WEST;
					}
					
				}
				if(map[mob[b].y-1][mob[b].x].scent > 10)
				{
					if(map[mob[b].y - 1][mob[b].x].scent > a)
					{
						a = map[mob[b].y - 1][mob[b].x].scent;
						dir = NORTH;
					}
					
				}
				
				if (dir == -1 )
				{
					dir = rand(4);
				}
	
					switch ( dir )
					{
					case NORTH:
						p.setLocation(mob[b].x + 0, mob[b].y - 1);
						mob[b].dir = 3;
						break;
					case EAST:
						p.setLocation(mob[b].x + 1, mob[b].y + 0);
						mob[b].dir = 0;
						break;
					case SOUTH:
						p.setLocation(mob[b].x + 0, mob[b].y + 1);
						mob[b].dir = 1;
						break;
					case WEST:
						p.setLocation(mob[b].x - 1, mob[b].y + 0);
						mob[b].dir = 2;
						break;

				}
					
			}
			if (!isBlocked(p))
			{
				if (!map[p.y][p.x].isOccupied())
				{

					mob[b].move(p);
				}
			}
			map[mob[b].y][mob[b].x].setMob(b);
		}
	}

	static int rand(int max)
	{
		return (int) (Math.random() * max);
	}

	private int getTile(int x, int y)
	{
		int i;

		if (map[y][x].isOccupied())
		{
			i = mob[map[y][x].getTile()].i + mob[map[y][x].getTile()].dir;
		}
		else
		{
			i = map[y][x].getFloor();
		}

		//
		// This limited the player's LOS. I used it to test the LOS code.
		//
		/*
		 * if (lineOfSight(player, x, y)) { if (map[y][x].isOccupied()) { i =
		 * mob[map[y][x].getTile()].i + mob[map[y][x].getTile()].dir; } else { i
		 * = map[y][x].getFloor(); } } else { if (isBlocked(x, y)) { i = 6; }
		 * else { i = 61; } }
		 */
		return i;
	}

	//
	// m is the mob looking around and p is the player
	//

	private boolean lineOfSight(Creature m, int p_x, int p_y)
	{
		int t, x, y, ax, ay, sx = 0, sy = 0, dx, dy;

		// Check to see if they're on the same space
		if (m.x == p_x && m.y == p_y)
		{
			return true;
		}
		// Delta x/y is the players x/y minus the monsters x/y
		dx = p_x - m.x;
		dy = p_y - m.y;

		/*
		 * ax & ay: these are the absolute values of dx & dy * multiplied by 2 (
		 * shift left 1 position)
		 */
		ax = Math.abs(dx) << 1;
		ay = Math.abs(dy) << 1;

		/* sx & sy: these are the signs of dx & dy */
		if (dx < 0)
		{
			sx = -1;
		}
		else
		{
			sx = 1;
		}
		if (dy < 0)
		{
			sy = -1;
		}
		else
		{
			sy = 1;
		}

		x = m.x;
		y = m.y;

		/*
		 * The following if statement checks to see if the line is x dominate or
		 * y dominate and loops accordingly
		 */
		if (ax > ay)
		{
			/* X dominate loop */
			/*
			 * t = the absolute of y minus the absolute of x divided * by 2
			 * (shift right 1 position)
			 */
			t = ay - (ax >> 1);
			do
			{
				if (t >= 0)
				{
					/*
					 * if t is greater than or equal to zero then * add the sign
					 * of dy to y * subtract the absolute of dx from t
					 */
					y += sy;
					t -= ax;
				}

				/*
				 * add the sign of dx to x * add the absolute of dy to t
				 */
				x += sx;
				t += ay;

				/* check to see if we are at the player's position */
				if (x == p_x && y == p_y)
				{
					/* return that the monster can see the player */
					return true;
				}
				/*
				 * keep looping until the monster's sight is blocked * by an
				 * object at the updated x,y coord
				 */
			}
			while (isBlocked(x, y) == false);

			return false;
		}
		else
		{
			/* Y dominate loop, this loop is basically the same as the x loop */
			t = ax - (ay >> 1);
			do
			{
				if (t >= 0)
				{
					x += sx;
					t -= ay;
				}
				y += sy;
				t += ax;
				if (x == p_x && y == p_y)
				{
					return true;
				}
			}
			while (isBlocked(x, y) == false);
			return false;
		}
	}

	private boolean isBlocked(int x, int y)
	{
		return map[y][x].isBlocked();
	}

	private boolean isBlocked(Point p)
	{
		return map[p.y][p.x].isBlocked();
	}

	public void spreadScent()
	{
		for (int h = 0; h < getHeight(); ++h)
		{
			for (int w = 0; w < getWidth(); ++w)
			{
				if (map[h][w].isBlocked())
				{
					scentMap[h][w] = 0;
					map[h][w].scent *= 0.75;
				}
				else
				{
					scentMap[h][w] = map[h][w].scent;
				}
			}
		}
		int a = 0, s = 0;
		for (int h = 0; h < getHeight(); ++h)
		{
			for (int w = 0; w < getWidth(); ++w)
			{
				if (!map[h][w].isBlocked())
				{
					a = 1; // Accumulator
					s = scentMap[h][w]; // aggregate scent value

					if (h - 1 >= 0)
					{
						s += scentMap[h - 1][w];
						if (scentMap[h - 1][w] > 0) a = a + 1;
					}
					if (h + 1 < getHeight())
					{
						s += scentMap[h + 1][w];
						if (scentMap[h + 1][w] > 0) a = a + 1;
					}
					if (w - 1 >= 0)
					{
						s += scentMap[h][w - 1];
						if (scentMap[h][w - 1] > 0) a = a + 1;
					}
					if (w + 1 < getWidth())
					{
						s += scentMap[h][w + 1];
						if (scentMap[h][w + 1] > 0) a = a + 1;
					}

					map[h][w].scent = Math.min(s / a, 100);
					if (map[h][w].scent == scentMap[h][w])
					{
						map[h][w].scent *= 0.75;
					}
				}
			}
		}

	}

	public void drawScent()
	{
		String s;
		for (int h = 0; h < getHeight(); ++h)
		{
			s = "";
			for (int w = 0; w < getWidth(); ++w)
			{
				s = s + map[h][w].scent + " ";
			}
			System.out.println(s);
			// console.addLine(s);
		}

	}
}
